var KUVIO = {};

KUVIO.config = {
    DebugMode: true
};


KUVIO.lang = {
    impl: function(obj, iface) {
        if (typeof obj == "object" && typeof iface == "object") {
            for (var p in iface) {
                if (typeof obj[p] !== typeof iface[p]) {
                    return false;
                }
            }
        }
        else if (typeof obj == "function" && typeof iface == "function" && obj.length < iface.length) {
            return false;
        }
        else if (typeof obj !== typeof iface) {
            return false;
        }
        return true;
    },
    isElement: function(el) {
        return ('undefined' !== typeof el.tagName &&
			'undefined' !== typeof el.nodeType);
    },
    isString: function(s) {
        return (typeof s === "string");
    },
    isNumber: function(n) {
        return (typeof n === "number");
    },
    isObject: function(o) {
        return (typeof o === "object");
    },
    isFunction: function(f) {
        return (typeof f === "function");
    },
    isArray: function(a) {
        if (KUVIO.lang.isObject(a)) {
            return (null !== a.constructor.toString().match(/Array/i));
        }
        else {
            return false;
        }
    },
    fold: function(list, func, initial, scope) {
        var rv = null;
        if (!Array.prototype.reduce && KUVIO.lang.isArray(list) && KUVIO.lang.isFunction(func) && func.length === 2) {
            if (list.length > 1) {
                var i = 0;
                if (initial !== null && list[initial] !== null) {
                    rv = list[initial];
                    i = initial;
                }
                else {
                    rv = null;
                }

                for (; i < list.length; i++) {
                    rv = func.call(scope, rv, list[i]);
                }
            }
            else {
                rv = list[0];
            }
        }
        return rv;
    },
    strhelper: function(s, v) {
        if (KUVIO.lang.isArray(v)) {
            for (var i = 0; i < v.length; i++) {
                s = s.replace("{" + i + "}", v[i]);
                return s;
            }
        }
        else return "";
    },
    clone: function(o) {
        if (typeof o !== "object") { return o; }
        var c = {};
        c.prototype = o.prototype;
        for (p in o) {
            if (o.hasOwnProperty(p)) {
                c[p] = o[p];
            }
        }
        return c;
    }
};

KUVIO.interfaces = {};
KUVIO.interfaces.IEventListener = {
    _fn: function() { },
    _sc: {}
};

KUVIO.event = {};

/***********************************************************************
*********       KUVIO.event.CustomEvent Object                  ********
***********************************************************************/

KUVIO.event.CustomEvent = function(name, defaultScope, listenerInterface, data) {
    // <summary>A custom event object that listeners added to, and invoked.</summary>
    // <param name="name">Event name</param>
    // <param name="defaultScope">If no scope is defined in the listener, this scope will be used.</param>
    // <param name="listenerInterface">Optional. Interface that the listener functions must implement.</param>
    this.name = name;
    this.scope = defaultScope;
    this.expectedInterface = listenerInterface || null;
    this.data = data;
    this.listeners = [];
    this.firing = false;
};
KUVIO.event.CustomEvent.prototype = {
    fire: function(data) {
        /// <summary>Fires the event</summary>
        /// <param name="data">An object to be passed to the listeners.</param>
        var d = {
            data: data,
            event: this
        };
        for (var i = 0; i < this.listeners.length; i++) {
            var s = this.listeners[i]._sc || this.defaultScope || null;
            try {
                this.listeners[i]._fn.call(s, this, d);
            }
            catch (e) {
                // In debug mode, log any errors to the error logging object. 
                // If firebug is available, they will appear in the console.
                // If not in debug mode, error is absorbed and next listener
                // is called.
                if (KUVIO.config.DebugMode) {
                    KUVIO.Log.error(e + ": Error in " +
                    ((this.listeners[i]._fn.name) ?
                        this.listeners[i]._fn.name :
                        this.listeners[i]._fn.toString
                    )
                );
                }
                continue;
            }
        }
    },
    addListener: function(func, scope) {
        // <summary>Adds an event listener to to the custom event.</summary>
        // <param name="func">Can be either a function or a reference to an EventListener.</param>
        // <param name="scope">(optional) scope to call the event listener in.</param>
        var l = null;
        if (KUVIO.lang.impl(func, KUVIO.interfaces.IEventListener)) {
            this.addListenerFromEventListener(func);
        }
        else {
            if ((this.expectedInterface && KUVIO.lang.impl(func, this.expectedInterface)) || !this.expectedInterface) {
                l = new KUVIO.event.EventListener(func, scope);
                this.listeners.push(l);
            }
        }
        return l;
    },
    addListenerAsEventListener: function(listener) {
        // <summary>Adds an Event Listener that implements KUVIO.interfaces.IEventListener</summary>
        // <param name="el">EventListener which implements KUVIO.interfaces.IEventListener</summary>
        if (KUVIO.lang.impl(listener, KUVIO.interfaces.IEventListener)) {
            this.listeners.push(listener);
            return listener;
        }
        else {
            return null;
        }
    },
    removeListenerAsEventListener: function(listener) {
        // <summary> Removes an event listener given an EventListener object </summary>
        // <param name="listener">EventListener which implements KUVIO.interfaces.IEventListener</summary>
        // <returns>The EventListener removed, if found. If not found, returns null.</returns>
        for (var i = 0; i < this.listeners.length; i++) {
            if (this.listeners[i] === listener) {
                return this.listeners.splice(i, 1);
            }
        }
        return null;
    },
    removeListener: function(func) {
        // <summary> Removes an event listener given either an EventListener object or a callback reference to remove.</summary>
        // <param name="func">EventListener or function reference</param>
        if (KUVIO.lang.impl(func, KUVIO.interfaces.IEventListener)) {
            return this.removeListenerAsEventListener(func);
        }
        for (var i = 0; i < this.listeners.length; i++) {
            if (this.listeners[i]._fn === func) {
                this.listeners.splice(i, 1);
            }
        }
    }


};

/***********************************************************************
*********       KUVIO.event.EventListener Object               *********
***********************************************************************/

KUVIO.event.EventListener = function(func, scope) {
    //<summary>Event Listener object. Implements KUVIO.interfaces.IEventListener</summary>
    //<param name="func">Function to invoke when the event fires.</param>
    //<param name="scope">The scope to call func in.</param>
    if (typeof func === "function" && typeof scope === "object") {
        this._fn = func;
        this._sc = scope;
    }
    else return null;
    KUVIO.lang.impl(this, KUVIO.interfaces.IEventListener);
};
KUVIO.event.EventListener.prototype = {
    invoke: function(data) {
        //<summary Invokes the callback function</summary>
        //<param name="data">Data to pass to the callback function</param>
        this._fn.call(this._sc, data);
    }
};

/************************************************************
KUVIO.Log
Error logging object.
************************************************************/

KUVIO.Log = (function() {
    if (!KUVIO.config.Logging) {
        return;
    };
    this.errors = [];
    this.error = function(e) {
        this.errors.push(e);
    };
    this.report = function() {
        KUVIO.lang.fold(this.errors, function(e) {
            if (console) {
                console.log(e);
            }
            else {
                alert(e);
            }
        });
    };
    this.onError = new KUVIO.event.CustomEvent("error", this);
})();


/************************************************************
KUVIO.connection
************************************************************/

KUVIO.connection = {};
KUVIO.connection.createBaseRequest = function() {
    ///<summary>Creates a cross-browser XHMLHttpRequest object</summary>
    if (XHMLHttpRequest) {
        return new XHMLHttpRequest();
    }
    else if (ActiveXObject) {
        try {
            return new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch (e) {
            return new ActiveXObject("Microsoft.XMLHTTP");
        }
        finally {
            return null;
        }
    }
};


KUVIO.connection.XHR = function(config, extraData) {
    ///<summary>Creates an XMLHttpRequest object with event hooks, etc</summary>
    ///<param name="config"></param>
    ///<param name="extraData">A data object that's passed along to event listeners</param>

    this.extraData = extraData;
    /* initialze events */
    this.onSetUp = new KUVIO.event.CustomEvent("xhrSetup", this);
    this.onConnectionOpen = new KUVIO.event.CustomEvent("xhrConnectionOpen", this);
    this.onSent = new KUVIO.event.CustomEvent("xhrSent", this);
    this.onProcessing = new KUVIO.event.CustomEvent("xhrProcessing", this);
    this.onComplete = new KUVIO.event.CustomEvent("xhrComplete", this);
    this.onFailure = new KUVIO.event.CustomEvent("xhrFailure", this);
    this.onSuccess = new KUVIO.event.CustomEvent("xhrSuccess", this);
    this.onTimeout = new KUVIO.event.CustomEvent("xhrTimeout", this);

    /* initialize XHR object */
    this._xhr = KUVIO.connection.createBaseRequest();
    this._xhr.onreadystatechange = this.readyStateChange;

    /* initialize timeout handler */
    if (config.timeout) {
        var that = this;
        this.onTimeout = function() {
            that._xhr.abort();
        };
    }
};

KUVIO.connection.XHR.prototype = {
    onSetUp: null,
    onConnectionOpen: null,
    onSent: null,
    onProcessing: null,
    onComplete: null,
    open: function() { },
    timeoutHandler: function() { },
    readyStateChange: function() {
        ///<summary>Handles the different ready states of the XHR, and fires appropriate events</summary>
        var d = {
            xhr: this,
            customData: this.extraData
        };
        switch (this._xhr.readyState) {
            case 0: this.onSetUp.fire(d);
                break;
            case 1: this.onConnectionOpen.fire(d);
                break;
            case 2: this.onSent.fire(d);
                break;
            case 3: this.onProcessing.fire(d);
                break;
            case 4:
                if (this._xhr.status !== 200) {
                    d.errorCode = this._xhr.status;
                    d.errorText = this._xhr.statusText;
                    this.onFailure.fire(d);
                }
                else {
                    this.onSuccess.fire(d);
                }
                this.onComplete.fire(d);
                break;
        }
    }
};


/************************************************************
KUVIO.structure
Defines Page and Module objects for use in organizing
your codebase.
************************************************************/
KUVIO.structure = {};
KUVIO.structure.Module = function(mod, parent) {
    var m = new mod();
    var hasInit = false;
    m.initialized = function() {
        return hasInit;
    }
    m.init();
    var hasInit = true;
};



KUVIO.structure.Page = function(init) {
    var p = new Module(init);

}
	
	
	
	